package org.hit.burkun.network.models;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Set;
import java.util.Map.Entry;

import org.hit.burkun.network.EdgeInfo;
import org.hit.burkun.network.SerializableGraph;
import org.hit.burkun.network.Vertex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SimpleSimRank {
	//http://www.cnblogs.com/zhangchaoyang/articles/4575809.html
	public static void main(String[] args) {
		SerializableGraph sg = StaticMethods.loadGraphNoDir();
		SimpleSimRank ssr = new SimpleSimRank(sg);
		ssr.iterRanker();
	}
	private static Logger log = LoggerFactory.getLogger(SimpleSimRank.class);
	protected HashMap<Vertex, LinkedList<EdgeInfo>> matrix = new HashMap<Vertex, LinkedList<EdgeInfo>>();
	private SerializableGraph sg = new SerializableGraph();
	public SimpleSimRank(SerializableGraph sg){
		data = new float[sg.getAllVertexs().size()][sg.getAllVertexs().size()];
		for(int i=0; i<data.length; i++){
			data[i][i] = 1;
		}
		this.sg = sg;
		reverseEdges(false);
	}
	
	private float[][] data;
	
	private void doOneRank(float zuni){
		log.debug("iter...");
		float[][] oldData = new float[sg.getAllVertexs().size()][sg.getAllVertexs().size()];
		Collection<Vertex> vs = sg.getAllVertexs();
		for(Vertex v1 : vs){
			log.debug("for vertex " + v1);
			for(Vertex v2 : vs){
				int i=v1.getUid();
				int j=v2.getUid();
				if(v1.getUid() != v2.getUid()){
					float sums = 0;
					LinkedList<EdgeInfo> ed1 = matrix.get(v1);
					LinkedList<EdgeInfo> ed2 = matrix.get(v2);
					if(ed1 == null || ed2 == null) break;
					for(EdgeInfo e1 : ed1){
						for(EdgeInfo e2 : ed2){
							sums += data[e1.getVertex().getUid()][e2.getVertex().getUid()];
						}
					}
					oldData[i][j] = sums*zuni/(ed1.size() * ed2.size());
 				}else{
 					oldData[i][j] = 1;
 				}
			}
		}
		computeError(data, oldData);
		data = oldData;
	}
	
	
	public void computeError(float[][] data, float[][] oldData){
		double sums = 0;
		for(int i=0; i<data.length; i++){
			for(int j=0; j<data.length; j++){
				sums = Math.max(Math.abs(data[i][j] - oldData[i][j]), sums);
			}
		}
		System.out.println(sums);
	}
	
	public void iterRanker(){
		for(int i=0; i<100; i++){
			doOneRank(0.9f);
		}
	}
	
	protected void reverseEdges(boolean useWeight) {
		log.debug("init matrix with weight...");
		HashMap<Vertex, LinkedList<EdgeInfo>> edges = sg.getEdgeMap();
		Set<Entry<Vertex, LinkedList<EdgeInfo>>> entries = edges.entrySet();
		SerializableGraph newSg = new SerializableGraph();
		for (Entry<Vertex, LinkedList<EdgeInfo>> entry : entries) {
			Vertex v = entry.getKey();
			LinkedList<EdgeInfo> edge = entry.getValue();
			if (edge.size() != 0) {
				double sizeSum = edge.size();
				if (useWeight) {
					sizeSum = 0;
					for (EdgeInfo ei : edge) {
						sizeSum += ei.getScore();
					}
				}
				for (EdgeInfo ei : edge) {
					// reverse edges
					// reverse edges
					EdgeInfo eei = null;
					if(useWeight){
						//使用自带的权值更新
						eei = new EdgeInfo(v, ei.getRelType());
						eei.setScore(ei.getScore() / sizeSum);
					}else{
						//不使用权值，当使用权值的时候，会出现所有权值消失的怪事儿
						eei = new EdgeInfo(v, ei.getRelType());
						eei.setScore(1 / sizeSum);
					}
					newSg.addEdge(ei.getVertex(), eei);
				}
			}
		}
		matrix = newSg.getEdgeMap();
		log.debug("init matrix with weight done!");
	}
}
